package com.sxkf.system.controller;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sxkf.core.api.vo.R;
import com.sxkf.template.entity.User;
import com.sxkf.template.service.UserService;
import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.Md5Util;
import org.jeecg.common.util.PasswordUtil;
import org.jeecg.common.util.RedisUtils;
import com.sxkf.system.entity.SysDepart;
import com.sxkf.system.entity.SysUser;
import com.sxkf.system.model.SysLoginModel;
import com.sxkf.system.service.ISysDepartService;
import com.sxkf.system.service.ISysDictService;
import com.sxkf.system.service.ISysLogService;
import com.sxkf.system.service.ISysUserService;
import com.sxkf.system.util.RandImageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.base.service.BaseCommonService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @since 2018-12-17
 */
@RestController
@RequestMapping("/sys")
@Api(tags="后台用户登录")
@Slf4j
public class SysLoginController {
	@Autowired
	private ISysUserService sysUserService;
	@Autowired
	private ISysLogService logService;
	@Autowired
    private RedisUtils redisUtils;
	@Autowired
    private ISysDepartService sysDepartService;
	@Autowired
    private ISysDictService sysDictService;
	@Autowired
	private BaseCommonService baseCommonService;
	@Autowired
	private JeecgBaseConfig jeecgBaseConfig;
    @Autowired
    private UserService userService;

	public static void main(String[] args) {
		String userPassword = PasswordUtil.encrypt("admin", "123456", "BrWJqYy6");
		System.out.println(userPassword);
		System.out.println("0d792ebcde594cf7".equals(userPassword));
	}

	@ApiOperation("登录接口")
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public R<JSONObject> login(@RequestBody SysLoginModel sysLoginModel){
		String username = sysLoginModel.getUsername();
		String password = sysLoginModel.getPassword();
		log.info("username:{},password:{}",username,password);
		//update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题
		//前端密码加密，后端进行密码解密
		//password = AesEncryptUtil.desEncrypt(sysLoginModel.getPassword().replaceAll("%2B", "\\+")).trim();//密码解密
		//update-begin--Author:scott  Date:20190805 for：暂时注释掉密码加密逻辑，有点问题

//        String captcha = sysLoginModel.getCaptcha();
//        if(captcha==null){
//            return R.error("验证码无效");
//        }
//        String lowerCaseCaptcha = captcha.toLowerCase();
//		// 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
//        String origin = lowerCaseCaptcha+sysLoginModel.getCheckKey()+jeecgBaseConfig.getSignatureSecret();
//		String realKey = Md5Util.md5Encode(origin, "utf-8");
//		Object checkCode = redisUtils.get(realKey);
//		//当进入登录页时，有一定几率出现验证码错误 #1714
//		if(checkCode==null || !checkCode.toString().equals(lowerCaseCaptcha)) {
//            log.warn("验证码错误，key= {} , Ui checkCode= {}, Redis checkCode = {}", sysLoginModel.getCheckKey(), lowerCaseCaptcha, checkCode);
//			return R.error(HttpStatus.PRECONDITION_FAILED.value(),"验证码错误");
//		}

		//1. 校验用户是否有效
		LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(SysUser::getUsername,username);
		SysUser sysUser = sysUserService.getOne(queryWrapper);
		sysUserService.checkUserIsEffective(sysUser);

		//User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getSysUserId, sysUser.getId()));

		log.info("sysUser:{}",JSONObject.toJSONString(sysUser));
		//2. 校验用户名或密码是否正确
		String userPassword = PasswordUtil.encrypt(password, sysUser.getUsername(), sysUser.getSalt());
		String sysPassword = sysUser.getPassword();
		if (!sysPassword.equals(userPassword)) {
			return R.error("用户名或密码错误");
		}

		//用户登录信息
		R<JSONObject> result = userInfo(sysUser);
		//登录成功，删除redis中的验证码
		//redisUtils.del(realKey);
		LoginUser loginUser = new LoginUser();
		BeanUtils.copyProperties(sysUser, loginUser);
		baseCommonService.addLog("用户名: " + username + ",登录成功！", CommonConstant.LOG_TYPE_1, null,loginUser);
		return result;
	}

	
	/**
	 * 退出登录
	 */
	@RequestMapping(value = "/logout")
	public R<Object> logout(HttpServletRequest request, HttpServletResponse response) {
		//用户退出逻辑
	    String token = request.getHeader(CommonConstant.X_ACCESS_TOKEN);
	    if(oConvertUtils.isEmpty(token)) {
	    	return R.error("退出登录失败！");
	    }
	    String username = JwtUtil.getUsername(token);
		LoginUser sysUser = sysUserService.getEncodeUserInfo(username);
	    if(sysUser!=null) {
			//update-begin--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
			baseCommonService.addLog("用户名: "+sysUser.getRealname()+",退出成功！", CommonConstant.LOG_TYPE_1, null,sysUser);
			//update-end--Author:wangshuai  Date:20200714  for：登出日志没有记录人员
	    	log.info(" 用户名:  "+sysUser.getRealname()+",退出成功！ ");
	    	//清空用户登录Token缓存
	    	redisUtils.del(CommonConstant.PREFIX_ADMIN_TOKEN + token);
	    	//清空用户登录Shiro权限缓存
			redisUtils.del(CommonConstant.PREFIX_ADMIN_SHIRO_CACHE + sysUser.getId());
			//清空用户的缓存信息（包括部门信息），例如sys:cache:user::<username>
			redisUtils.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
			//调用shiro的logout
			SecurityUtils.getSubject().logout();
	    	return R.success("退出登录成功！");
	    }else {
	    	return R.error("Token无效!");
	    }
	}
	
	/**
	 * 获取访问量
	 */
	@GetMapping("loginfo")
	public R<JSONObject> loginfo() {
		JSONObject obj = new JSONObject();
		//update-begin--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
		// 获取一天的开始和结束时间
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.HOUR_OF_DAY, 0);
		calendar.set(Calendar.MINUTE, 0);
		calendar.set(Calendar.SECOND, 0);
		calendar.set(Calendar.MILLISECOND, 0);
		Date dayStart = calendar.getTime();
		calendar.add(Calendar.DATE, 1);
		Date dayEnd = calendar.getTime();
		// 获取系统访问记录
		Long totalVisitCount = logService.findTotalVisitCount();
		obj.put("totalVisitCount", totalVisitCount);
		Long todayVisitCount = logService.findTodayVisitCount(dayStart,dayEnd);
		obj.put("todayVisitCount", todayVisitCount);
		Long todayIp = logService.findTodayIp(dayStart,dayEnd);
		//update-end--Author:zhangweijian  Date:20190428 for：传入开始时间，结束时间参数
		obj.put("todayIp", todayIp);
		return R.success(obj);
	}
	
	/**
	 * 获取访问量
	 */
	@GetMapping("visitInfo")
	public R<List<Map<String,Object>>> visitInfo() {
		R<List<Map<String,Object>>> r = new R<List<Map<String,Object>>>();
		Calendar calendar = new GregorianCalendar();
		calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);
        calendar.add(Calendar.DAY_OF_MONTH, 1);
        Date dayEnd = calendar.getTime();
        calendar.add(Calendar.DAY_OF_MONTH, -7);
        Date dayStart = calendar.getTime();
        List<Map<String,Object>> list = logService.findVisitCount(dayStart, dayEnd);
		return R.success(oConvertUtils.toLowerCasePageList(list));
	}
	
	
	/**
	 * 登陆成功选择用户当前部门
	 * @param user
	 * @return
	 */
	@RequestMapping(value = "/selectDepart", method = RequestMethod.PUT)
	public R<JSONObject> selectDepart(@RequestBody SysUser user) {
		String username = user.getUsername();
		if(oConvertUtils.isEmpty(username)) {
			LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal();
			username = sysUser.getUsername();
		}
		String orgCode= user.getOrgCode();
		this.sysUserService.updateUserDepart(username, orgCode);
		SysUser sysUser = sysUserService.getUserByName(username);
		JSONObject obj = new JSONObject();
		obj.put("userInfo", sysUser);
		return R.success(obj);
	}

	/**
	 * 用户信息
	 */
	private R<JSONObject> userInfo(SysUser sysUser) {
		String username = sysUser.getUsername();
		String sysPassword = sysUser.getPassword();
		// 获取用户部门信息
		JSONObject obj = new JSONObject(new LinkedHashMap<>());

		// 生成token
		String token = JwtUtil.sign(username, sysPassword);
		// 设置token缓存有效时间
		redisUtils.set(CommonConstant.PREFIX_ADMIN_TOKEN + token, token);
		redisUtils.expire(CommonConstant.PREFIX_ADMIN_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
		obj.put("token", token);

		obj.put("userInfo", sysUser);

		List<SysDepart> departs = sysDepartService.queryUserDeparts(sysUser.getId());
		obj.put("departs", departs);
		if (departs == null || departs.isEmpty()) {
			obj.put("multi_depart", 0);
		} else if (departs.size() == 1) {
			sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
			obj.put("multi_depart", 1);
		} else {
			//查询当前是否有登录部门
			// update-begin--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
			SysUser sysUserById = sysUserService.getById(sysUser.getId());
			if(oConvertUtils.isEmpty(sysUserById.getOrgCode())){
				sysUserService.updateUserDepart(username, departs.get(0).getOrgCode());
			}
			// update-end--Author:wangshuai Date:20200805 for：如果用戶为选择部门，数据库为存在上一次登录部门，则取一条存进去
			obj.put("multi_depart", 2);
		}
		obj.put("sysAllDictItems", sysDictService.queryAllDictItems());
		return R.success(obj);
	}


	/**
	 * 后台生成图形验证码 ：有效
	 * @param key
	 */
	@ApiOperation("获取验证码")
	@GetMapping(value = "/randomImage/{key}")
	public R<String> randomImage(@PathVariable("key") String key){
		try {
			//生成验证码
            String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";
            String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
			//存到redis中
			String lowerCaseCode = code.toLowerCase();
			
			// 加入密钥作为混淆，避免简单的拼接，被外部利用，用户自定义该密钥即可
			String origin = lowerCaseCode+key+jeecgBaseConfig.getSignatureSecret();
			String realKey = Md5Util.md5Encode(origin, "utf-8");

			redisUtils.set(realKey, lowerCaseCode, 60);
			log.info("获取验证码，Redis key = {}，checkCode = {}", realKey, code);
			//返回前端
			String base64 = RandImageUtil.generate(code);
			return R.success(base64);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return R.error("获取验证码失败,请检查redis配置!");
		}
	}

	@ApiOperation(value = "校验图形验证码")
	@RequestMapping(value = "/checkCaptcha", method = RequestMethod.POST)
	public R<?> checkCaptcha(@RequestBody SysLoginModel sysLoginModel){
		String captcha = sysLoginModel.getCaptcha();
		String checkKey = sysLoginModel.getCheckKey();
		if(captcha==null){
			return R.error("验证码无效");
		}
		String lowerCaseCaptcha = captcha.toLowerCase();
		String realKey = Md5Util.md5Encode(lowerCaseCaptcha+checkKey, "utf-8");
		Object checkCode = redisUtils.get(realKey);
		if(checkCode==null || !checkCode.equals(lowerCaseCaptcha)) {
			return R.error("验证码错误");
		}
		return R.success();
	}

}